package com.hwy.widget.xx_ui.widget

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import com.hwy.widget.R
import kotlin.math.max

/**
 * =======================================
 * 作者: hewenyu
 * 日期: 2022/4/5 22:16
 * 说明: 流式布局
 * =======================================
 */
class FlowLayout : FrameLayout {

    /**
     * 存储每一行的View数组
     */
    private val lineChildrenList by lazy {
        ArrayList<ArrayList<View>>()
    }

    /**
     * 记录每一行的高度
     */
    private val lineHeightList by lazy {
        ArrayList<Int>()
    }

    /**
     * 每个view横向的间距
     */
    private var horizontalOffset = 0

    /**
     * 每个view纵向的间距
     */
    private var verticalOffset = 0

    private var adapter: Adapter? = null

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        val typeArray = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout)
        horizontalOffset = typeArray.getDimensionPixelSize(
            R.styleable.FlowLayout_horizontalOffset,
            horizontalOffset
        )
        verticalOffset =
            typeArray.getDimensionPixelOffset(R.styleable.FlowLayout_verticalOffset, verticalOffset)
        typeArray.recycle()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        lineChildrenList.clear()
        lineHeightList.clear()
        var width = MeasureSpec.getSize(widthMeasureSpec)
        var height = MeasureSpec.getSize(heightMeasureSpec)
        // 记录children排版后的高度
        var totalHeight = paddingTop + paddingBottom
        // 行高
        var lineMaxHeight = 0
        // 记录行号
        var column = 0
        // 记录每一行使用的宽度
        var lineUsedWidth = paddingLeft + paddingRight

        for (i in 0 until childCount) {
            val view = getChildAt(i)
            if (view.visibility == View.GONE) {
                continue
            }
            // 测量子控件
            measureChild(view, widthMeasureSpec, heightMeasureSpec)
            val childWidth = view.measuredWidth
            val childHeight = view.measuredHeight
            if (lineUsedWidth + childWidth + horizontalOffset > width) {
                // 换行
                // 1.更新当前行的最大高度
                lineHeightList.add(lineMaxHeight)
                // 2.更新总高度
                totalHeight += verticalOffset + lineMaxHeight
                // 3.换行后的高度从改行的第一个view开始记录
                lineMaxHeight = childHeight
                // 4.更新行号
                column++
                // 5.更新已使用的宽度
                lineUsedWidth = paddingLeft + paddingRight + childWidth
                // 6.加入容器
                getChildrenListByColumn(column)?.add(view)
            } else {
                // 记录更新后的宽度
                lineUsedWidth += horizontalOffset + childWidth
                // 更新最大高度
                lineMaxHeight = max(lineMaxHeight, childHeight)
                // 加入容器管理
                getChildrenListByColumn(column)?.add(view)
            }
            // 最后一行需要手动判断增加行高
            if (i == childCount - 1) {
                lineHeightList.add(lineMaxHeight)
                totalHeight += verticalOffset + lineMaxHeight
            }
        }

        val realHeight =
            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) height else totalHeight
        // 设置父容器高度
        setMeasuredDimension(width, realHeight)
    }

    private fun getChildrenListByColumn(column: Int): ArrayList<View>? {
        return if (column >= 0 && column < lineChildrenList.size) {
            lineChildrenList[column]
        } else if (column == lineChildrenList.size) {
            val list = ArrayList<View>()
            lineChildrenList.add(list)
            list
        } else {
            null
        }
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        val lineCount = lineChildrenList.size
        var startX = paddingLeft
        var startY = paddingTop
        for (i in 0 until lineCount) {
            val childrenList = lineChildrenList[i]
            childrenList.forEach { view ->
                view.layout(
                    startX,
                    startY,
                    startX + view.measuredWidth,
                    startY + view.measuredHeight
                )
                // 更新横向偏移量
                startX += view.measuredWidth + horizontalOffset
            }
            // 换行时，更新横向和纵向偏移量
            startX = paddingLeft
            startY += lineHeightList[i] + verticalOffset
        }
    }

    fun setAdapter(adapter: Adapter?) {
        removeAllViews()
        this.adapter = adapter?.apply {
            for (i in 0 until getCount()) {
                addView(getView(i))
            }
        }
        requestLayout()
        invalidate()
    }

    interface Adapter {

        fun getCount(): Int

        fun getView(position: Int): View

    }

}